iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
1
自我挑戰組

區塊鏈報明牌系列 第 3

[區塊鏈報明牌]Day 3 比特幣論文(2)-數位簽章

  • 分享至 

  • xImage
  •  

是說昨天才發現台大廖世偉教授去年就有開區塊鏈相關課程啦,早點察覺的話說不定就改題目了( ̄口 ̄!! ),而且在IThome也有很多介紹類的文章,在不想點梗搭配實在很沒看頭阿( ̄ㄧ ̄ ) 。

數位簽章

今天來講區塊鏈用到最重要的密碼學技術,什麼是數位簽章呢?簡單來說就是你有兩把鑰匙,一把叫公鑰(Public Key)、一把叫私鑰(Private Key),公鑰是發給所有人的,私鑰你要藏好,藏到其他人絕對看不到的地方。當你有某個資料要在網路上流傳時,用私鑰簽名證明這是你給的資料,其他人可以用公鑰來確認簽名的人是不是你。

沒有用過數位簽章經驗的人可能這樣想,我為什麼要在資料上簽名,我在fb傳東西從來沒人要我簽名阿,這東西一般一定用不到吧?其實不然,例如我們現在看的鐵人賽文章網頁全部都是數位簽章後才傳送的。想像一下如果今天開開心心寫了一隻程式編成執行檔後放到網路上給人用,結果被人偷塞病毒後放載點上來而大家都不知道,是多恐怖的事阿。

同樣的在接觸區塊鏈技術時,尤其是虛擬貨幣,一定要把私鑰藏好,私鑰是用來證明某筆虛擬貨幣是你的,別人拿到也可以說是他的然後全部領走。千萬不要放到某個網頁記事本或能讓瀏覽器紀錄的地方,有人破解進來之後寫個爬蟲把像私鑰跟地址的字串全部try一遍你的錢就沒了。

下圖是比特幣原始論文第二章的簽章流程,請注意該圖的運作是有問題的,並不能知道owner是不是重複花了比特幣兩次,只能證明比特幣是由擁有私鑰的owner所花掉,詳細的內容留到明天解釋:

先安裝python加密相關套件:

sudo pip install ecdsa

現在先用簡單的python code演示其中的數位簽章流程:

import ecdsa

sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) # 用比特幣使用的加密演算法產生私鑰
vk = sk.get_verifying_key() # 用私鑰產生公鑰

print(sk.to_pem())
"""
把私鑰印出來會類似這樣,真正的使用場景中絕對不要這樣印出來放到網頁上
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIGqXRqNjZns1TJ1CfayizUPcpZop00KWWj0+fOy/WwqtoAcGBSuBBAAK
oUQDQgAEZUBDWMgG3dTAzKcvMbw1IkJiLbtFq/AyLIMsKpz2v2mc3e3QJUM/scUR
MzoXPDSPftfU2CT6f4K0saWZsstAWg==
-----END EC PRIVATE KEY-----
"""

print(vk.to_pem())
"""
公鑰拿給別人來驗證簽名是不是你的
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEZUBDWMgG3dTAzKcvMbw1IkJiLbtFq/Ay
LIMsKpz2v2mc3e3QJUM/scURMzoXPDSPftfU2CT6f4K0saWZsstAWg==
-----END PUBLIC KEY-----
"""

transaction1 = vk.to_pem() + 'IThome2018' # 這裡先隨便塞data當作上一個transaction
                                          # 注意onwer1的公鑰也要加入

sk2 = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) # owner2的私鑰 
vk2 = sk2.get_verifying_key() # 用私鑰產生公鑰

sig = sk.sign(transaction1 + vk2.to_pem()) # 用上個transaction的內容與owner2的公鑰以owner1的私鑰進行簽名
                                         
print(sig.encode('hex'))
"""
簽名也是產生一段很長的字串,隨資料一起傳送
'04a3674e4f2027aedf91c7d5fd9786f4c9889579d197a38c50e1b8e6e883aa49fbb3f0712d01af10b7d86ef5b5591c23476a497fe80141c957106fca040d9719'

"""

vk.verify(sig, transaction1 + vk2.to_pem()) # 最後用公鑰和簽名來驗證資料是不是有被竄改

要詳細說明背後的密碼學原理絕對可以在開一篇30天,下面就簡單了解一下概念吧。

私鑰(Private Key)、公鑰(Public Key)

私鑰跟公鑰是非對稱加密(asymmetric cryptography)技術中最重要的部份,背後的數學原理在於用私鑰可以很容易算出一把公鑰來用,而公鑰很難去反推回私鑰。

例如隨便從已知的大質數中找兩個相乘:

618970019642690137449562111 *
162259276829213363391578010288127
= 100433627766186892221372630609062766858404681029709092356097

隨便拿個腳本語言計算一下兩個大質數相乘非常簡單。根據wiki的資料,目前用電腦計算出在10^23之下估計有1,925,320,391,606,803,968,923個質數,可見反推的難度,大家可以對非對稱計算難度的數學問題有一個概念。

橢圓曲線密碼系統 (Elliptic Curve Cryptosystem,簡稱ECC)

橢圓曲線密碼學是比特幣系統實作時所採用的加密系統,而secp256k1定義了裡面實際使用的一些參數,詳細的數學計算大家真的有興趣在自己去找吧,總之只要知道保護好私鑰就對了。

雪崩效應(Avalanche Effect)

IT技術人對hash大概都不陌生,可以想見hash會有collision,在密碼學中良好的hash function都會具有雪崩效應性質,也就是相似的資料會有很不一樣的hash值。

以下列wiki中SHA-1 hash function的示意圖來看,資料只差了一點點,hash值卻會幾乎完全改變。這對目前以交易、合約、流程紀錄來講的區塊鏈應用來說是非常好的性質,像是把交易金額偷改個0之類的事是不可能發生的。

在查資料的過程中發現去年的鐵人賽也有關於數位簽章的解釋,可以交叉參考幫助理解。

相關參考資源:

《Bitcoin: A Peer-to-Peer Electronic Cash System》
https://bitcoin.org/bitcoin.pdf
python-ecdsa
https://github.com/warner/python-ecdsa
質數列表
https://zh.wikipedia.org/wiki/%E8%B3%AA%E6%95%B8%E5%88%97%E8%A1%A8
雪崩效應
https://en.wikipedia.org/wiki/Avalanche_effect


上一篇
[區塊鏈報明牌]Day 2 比特幣論文(1)-51%攻擊
下一篇
[區塊鏈報明牌]Day 4 比特幣論文(3)-Transactions, Timestamp Server
系列文
區塊鏈報明牌30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
mon820722
iT邦新手 5 級 ‧ 2018-03-09 13:32:51

你好 我是python的初學者
在github有下載你的程式來執行
在day4的部分,執行時會出現錯誤
line 27, in
'signature': owner0_sk.sign('假設中的transaction0' + owner1_vk.to_pem())
TypeError: must be str, not bytes
----------------------------------分隔線-------------------------------------
day5的部分也有相同的錯誤
line 91, in
transaction2 = trade(blockchain[0]['Txs'][0], '1000萬拿去收好', owner1_sk, owner2_vk)
line 73, in trade
'signature': pre_sk.sign(str(pre_tran) + now_vk.to_pem())
TypeError: must be str, not bytes

請問要如何修改呢?

willyc20 iT邦新手 5 級 ‧ 2018-03-09 19:32:04 檢舉

HI,

我想可能是你用python3的關西 一些type之間的關西有點不一樣
可以考慮改用python2看看

0
KCFeng
iT邦新手 5 級 ‧ 2019-06-01 10:22:38

剛開始研讀區塊鍊, 觀念還不是很懂, 請問進行簽名前為何不用先進行hash呢?

sig = sk.sign(transaction1 + vk2.to_pem()) # 用上個transaction的內容與owner2的公鑰以owner1的私鑰進行簽名

bitcoin論文中提到

Each owner transfer the coin to the next by digitally signing a hash of the previous transaction and the public key of the next owner and adding these to the end of the coin.

willyc20 iT邦新手 5 級 ‧ 2020-03-24 21:49:57 檢舉

HI 抱歉最近在整理過去的資料才看到這個回應。

可以查看這個:https://github.com/warner/python-ecdsa/issues/88

沒特別設定的話 sk.sign() 會先用 sha1 做 hash,希望有幫到忙。

我要留言

立即登入留言